
#include <pwm.h>
#include <rtthread.h>
static TIM_HandleTypeDef motor_tim;

static void motor_gpio_bsp_init(void)
{
    /*开启定时器相关的GPIO外设时钟*/
    MOTOR_1_GPIO_CLK_ENABLE();
    MOTOR_2_GPIO_CLK_ENABLE();
    MOTOR_3_GPIO_CLK_ENABLE();
    MOTOR_4_GPIO_CLK_ENABLE();

    /*定义一个GPIO_InitTypeDef类型的结构体*/
    GPIO_InitTypeDef GPIO_InitStructure;

    /* 定时器功能引脚初始化 */
    GPIO_InitStructure.Pin = MOTOR1_GPIO_PIN;
    GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStructure.Pull = GPIO_NOPULL;
    GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
    GPIO_InitStructure.Alternate = MOTOR1_GPIO_AF;
    HAL_GPIO_Init(MOTOR1_GPIO_GROUP, &GPIO_InitStructure);

    GPIO_InitStructure.Pin = MOTOR2_GPIO_PIN;
    GPIO_InitStructure.Alternate = MOTOR2_GPIO_AF;
    HAL_GPIO_Init(MOTOR2_GPIO_GROUP, &GPIO_InitStructure);

    GPIO_InitStructure.Pin = MOTOR3_GPIO_PIN;
    GPIO_InitStructure.Alternate = MOTOR3_GPIO_AF;
    HAL_GPIO_Init(MOTOR3_GPIO_GROUP, &GPIO_InitStructure);

    GPIO_InitStructure.Pin = MOTOR4_GPIO_PIN;
    GPIO_InitStructure.Alternate = MOTOR4_GPIO_AF;
    HAL_GPIO_Init(MOTOR4_GPIO_GROUP, &GPIO_InitStructure);
}

static void motor_tim_bsp_init(void)
{
    TIM_OC_InitTypeDef TIM_OCInitStructure = {0};

    // 开启TIMx_CLK,x[1,8]
    MOTOR_TIM_CLK_ENABLE();
    /* 定义定时器的句柄即确定定时器寄存器的基地址*/
    motor_tim.Instance = MOTOR_PWM_TIM;
    /* 累计 TIM_Period个后产生一个更新或者中断*/
    // 当定时器从0计数到999，即为1000次，为一个定时周期
    motor_tim.Init.Period = MOTOR_TIM_PERIOD;
    // 高级控制定时器时钟源TIMxCLK = HCLK=168MHz
    // 设定定时器频率为=TIMxCLK/(TIM_Prescaler+1)=1MHz
    motor_tim.Init.Prescaler = MOTOR_TIM_PRESCALER;
    // 采样时钟分频
    motor_tim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    // 计数方式
    motor_tim.Init.CounterMode = TIM_COUNTERMODE_UP;
    // 重复计数器
    motor_tim.Init.RepetitionCounter = 0;
    // 初始化定时器TIMx, x[1,8]
    HAL_TIM_PWM_Init(&motor_tim);

    /*PWM模式配置*/
    // 配置为PWM模式1
    TIM_OCInitStructure.OCMode = TIM_OCMODE_PWM1;
    TIM_OCInitStructure.Pulse = 0;
    TIM_OCInitStructure.OCPolarity = TIM_OCPOLARITY_HIGH;
    TIM_OCInitStructure.OCNPolarity = TIM_OCNPOLARITY_HIGH;
    TIM_OCInitStructure.OCIdleState = TIM_OCIDLESTATE_SET;
    TIM_OCInitStructure.OCNIdleState = TIM_OCNIDLESTATE_RESET;
    // 初始化通道1输出PWM
    HAL_TIM_PWM_ConfigChannel(&motor_tim, &TIM_OCInitStructure, MOTOR_1_CHANNEL);
    HAL_TIM_PWM_ConfigChannel(&motor_tim, &TIM_OCInitStructure, MOTOR_2_CHANNEL);
    HAL_TIM_PWM_ConfigChannel(&motor_tim, &TIM_OCInitStructure, MOTOR_3_CHANNEL);
    HAL_TIM_PWM_ConfigChannel(&motor_tim, &TIM_OCInitStructure, MOTOR_4_CHANNEL);

    /* 定时器通道1输出PWM */
    HAL_TIM_PWM_Start(&motor_tim, MOTOR_1_CHANNEL);
    HAL_TIM_PWM_Start(&motor_tim, MOTOR_2_CHANNEL);
    HAL_TIM_PWM_Start(&motor_tim, MOTOR_3_CHANNEL);
    HAL_TIM_PWM_Start(&motor_tim, MOTOR_4_CHANNEL);
}

int motor_pwm_init(void)
{
    motor_gpio_bsp_init();
    motor_tim_bsp_init();

    return 0;
}

int motor_run(enum motor_id motor_which, float duty_cycle)
{
    switch (motor_which)
    {
    case motor_1:
        __HAL_TIM_SetCompare(&motor_tim, MOTOR_1_CHANNEL, duty_cycle * MOTOR_TIM_PERIOD);
        break;

    case motor_2:
        __HAL_TIM_SetCompare(&motor_tim, MOTOR_2_CHANNEL, duty_cycle * MOTOR_TIM_PERIOD);
        break;

    case motor_3:
        __HAL_TIM_SetCompare(&motor_tim, MOTOR_3_CHANNEL, duty_cycle * MOTOR_TIM_PERIOD);
        break;

    case motor_4:
        __HAL_TIM_SetCompare(&motor_tim, MOTOR_4_CHANNEL, duty_cycle * MOTOR_TIM_PERIOD);
        break;
    default:
        break;
    }

    return 0;
}

static void motor_test(int argc, char **argv)
{
    if (argc < 2)
    {
        rt_kprintf("correct usage: motor_test <motor id> \nexample: motor_test 1 \n");
        return;
    }

    enum motor_id x_motor;
    if (rt_strcmp(argv[1], "1") == 0)
        x_motor = motor_1;
    else if (rt_strcmp(argv[1], "2") == 0)
        x_motor = motor_2;
    else if (rt_strcmp(argv[1], "3") == 0)
        x_motor = motor_3;
    else if (rt_strcmp(argv[1], "4") == 0)
        x_motor = motor_4;

    int duty = 20;
    for (; duty >= 0; duty -= 5)
    {
        if (x_motor == motor_1)
            __HAL_TIM_SetCompare(&motor_tim, MOTOR_1_CHANNEL, 1.0f * duty / 100 * MOTOR_TIM_PERIOD);
        else if (x_motor == motor_2)
            __HAL_TIM_SetCompare(&motor_tim, MOTOR_2_CHANNEL, 1.0f * duty / 100 * MOTOR_TIM_PERIOD);
        else if (x_motor == motor_3)
            __HAL_TIM_SetCompare(&motor_tim, MOTOR_3_CHANNEL, 1.0f * duty / 100 * MOTOR_TIM_PERIOD);
        else if (x_motor == motor_4)
            __HAL_TIM_SetCompare(&motor_tim, MOTOR_4_CHANNEL, 1.0f * duty / 100 * MOTOR_TIM_PERIOD);

        rt_thread_mdelay(2000);
    }
}
MSH_CMD_EXPORT(motor_test, "test motor control");
